package com.linkoog.devtools.utils;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.text.SimpleDateFormat;

/**
 * 基于Jackson的JSON转换工具类
 *
 * @author 20026272
 * @version 2018/6/29 12:06
 */
public class JacksonUtil {
    private JacksonUtil() {
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(JacksonUtil.class);

    private static final ObjectMapper objectMapper;

    static {
        objectMapper = new ObjectMapper();
        // 对象的所有字段全部列入，还是其他的选项，可以忽略null等
        objectMapper.setSerializationInclusion(Include.ALWAYS);
        // 设置Date类型的序列化及反序列化格式
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

        //是否允许解析使用Java/C++ 样式的注释（包括'/'+'*' 和'//' 变量）。
        objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        //是否允许单引号来包住属性名称和字符串值。
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        //是否将允许使用非双引号属性名字
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);


        // 忽略空Bean转json的错误
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 忽略未知属性，防止json字符串中存在，java对象中不存在对应属性的情况出现错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

        // 注册一个时间序列化及反序列化的处理模块，用于解决jdk8中localDateTime等的序列化问题
        //objectMapper.registerModule(new JavaTimeModule());
    }

    public static JsonNode readTree(String json) throws Exception{
        return objectMapper.readTree(json);
    }

    /**
     * 对象 => json字符串
     *
     * @param obj 源对象
     */
    public static <T> String toJson(T obj) {
        String json = null;
        if (obj != null) {
            try {
                json = objectMapper.writeValueAsString(obj);
            } catch (JsonProcessingException e) {
                LOGGER.error("toJson: {}", e.toString());
            }
        }
        return json;
    }

    public static <T> String toPrettyJson(T obj){
        String json = null;
        if (obj != null) {
            try {
                json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
            } catch (JsonProcessingException e) {
                LOGGER.error("toJson: {}", e.toString());
            }
        }
        return json;
    }

    /**
     * json字符串 => 对象
     *
     * @param json  源json串
     * @param clazz 对象类
     * @param <T>   泛型
     */
    public static <T> T parse(String json, Class<T> clazz) {
        return parse(json, clazz, null);
    }

    /**
     * json字符串 => 对象
     *
     * @param json 源json串
     * @param type 对象类型
     * @param <T>  泛型
     */
    public static <T> T parse(String json, TypeReference<T> type) {
        return parse(json, null, type);
    }

    /**
     * json => 对象处理方法
     * <br>
     * 参数clazz和type必须一个为null，另一个不为null
     * <br>
     * 此方法不对外暴露，访问权限为private
     *
     * @param json  源json串
     * @param clazz 对象类
     * @param type  对象类型
     * @param <T>   泛型
     */
    private static <T> T parse(String json, Class<T> clazz, TypeReference<T> type) {
        T obj = null;
        if (!isEmpty(json)) {
            if (clazz != null) {
                try {
                    obj = objectMapper.readValue(json, clazz);
                } catch (IOException e) {
                    LOGGER.error("readValue: {}", e.toString());
                }
            } else {
                try {
                    obj = objectMapper.readValue(json, type);
                } catch (IOException e) {
                    LOGGER.error("readValue: {}", e.toString());
                }
            }
        }
        return obj;
    }

    private static boolean isEmpty(CharSequence charSequence){
        return charSequence == null || charSequence.length() == 0;
    }


}

